﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Xml.Serialization;

namespace SteamWebAPI
{
    /// <summary>
    /// Jedna aktivní hra.
    /// </summary>
    [Serializable()]
    public class GameSession
    {
        public enum Teams
        {
            Radiant,
            Dire,
        }

        public event EventHandler Resolved;

        public event SessionChangedEventHandler Changed;

        private string name;

        [XmlElement("Name")]
        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

        [XmlElement("Team")]
        public Teams Team
        {
            get;
            set;
        }

        [XmlElement("Date")]
        public DateTime Date
        {
            get;
            set;
        }

        /// <summary>
        /// Seznam hráčů v dané hře.
        /// </summary>
        [XmlArray("players")]
        [XmlArrayItem("player", typeof(SteamUser))]
        public ObservableCollection<SteamUser> Players = new ObservableCollection<SteamUser>();

        private int progress;

        [System.Xml.Serialization.XmlIgnore]
        public int Progress
        {
            get { return this.progress; }
        }

        public override string ToString()
        {
            return this.name;
        }

        private string[] inputLines;

        private ArrayList names;

        public GameSession()
        {
            Date = DateTime.Now;
            name = "Game " + DateTime.Now.ToString();
        }

        /// <summary>
        /// Veřejný konstruktor
        /// </summary>
        /// <param name="data">Výpis z konzole na příkaz status</param>
        public GameSession(string data)
        {
            Date = DateTime.Now;
            names = new ArrayList();
            name = "Game " + DateTime.Now.ToString();
            inputLines = data.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            string pattern = @"STEAM_\d+:\d+:\d+";
            for (int i = 0; i < inputLines.Length; ++i)
            {
                if (inputLines[i].Contains("STEAM_"))
                {
                    Match result = Regex.Match(inputLines[i], pattern);
                    names.Add(result.Value);
                }
            }
            if (names.Count == 0)
                throw new SystemException("Empty input");
        }

        public void Resolve()
        {

            try
            {
                //this.progress = 0;
                if (names.Count == 0)
                    return;
                progress = 100 / names.Count;
                Players = new ObservableCollection<SteamUser>();

                string[] arrayNames = names.ToArray(typeof(string)) as string[];
                // Paralelně
                
                Parallel.ForEach(arrayNames,steamID=>
                {
                    SteamUser user = ObtainUser(steamID);
                    if (user != null)
                        Players.Add(user);
                });
                 
                // Sekvenčně
                /*
                foreach (string steamID in arrayNames)
                {
                    Players.Add(ObtainUser(steamID));
                }
                */
                if (Changed != null)
                    Changed(this, new SessionChangedEventArgs(progress, "Scanning friends..."));
                ScanFriends();

                if (Changed != null)
                    Changed(this, new SessionChangedEventArgs(progress, "Sorting list..."));

                ObservableCollection<SteamUser> sortedPlayers = new ObservableCollection<SteamUser>(Players.OrderByDescending(i => i.Group));
                Players.Clear();
                Players = sortedPlayers;
                if (Resolved != null)
                {
                    Resolved(this, EventArgs.Empty);
                }

            }
            catch (SystemException e)
            {
                throw;
            }
        }

        public DateTime? FindUser(SteamUser user)
        {
            int index = Players.IndexOf(user);
            if (index != -1)
                return this.Date;
            return null;
        }

        private void ScanFriends()
        {
            int freeGroup = 1;
            foreach (SteamUser player in Players)
            {
                if (player == null)
                    continue;
                // Nemá přátele nebo nejdou vidět.
                if (player.Friends == null)
                {
                    continue;
                }
                foreach (SteamUser friend in player.Friends)
                {
                    if (Players.Contains(friend))
                    {
                        // Najdeme si frienda jako playera
                        SteamUser player2 = Players[Players.IndexOf(friend)];
                        if (player.Group == 0 && player2.Group == 0)
                        {
                            player.Group = freeGroup++;
                            player2.Group = player.Group;
                        }
                        else if (player.Group == 0)
                        {
                            player.Group = player2.Group;
                        }
                        else
                        {
                            player2.Group = player.Group;
                        }
                    }
                }
            }
        }

        public SteamUser ObtainUser(string id)
        {
            SteamUser user = null;
            try
            {
                SteamQuery query = new SteamQuery();
                user = query.GetUserDetails(id);

                if (Changed != null)
                    Changed(this, new SessionChangedEventArgs(progress, "Scanning user " + id + "..."));
            }
            catch (SystemException e)
            {
                Console.WriteLine(e.ToString());
            }
            return user;
        }

        public static Int64 IdConvert(string id)
        {
            return 0;
        }

    }
}
